#ifndef UnstructMG_SEQ_MV_HPP
#define UnstructMG_SEQ_MV_HPP

#include "common.hpp"

template<typename idx_t, typename data_t, int dof>
class seq_Vector
{
public:
    data_t * data = nullptr;
    idx_t num = 0;

    long long tot_len = 0;

    seq_Vector(const idx_t num);
    seq_Vector(const seq_Vector & model);
    ~seq_Vector();

    void operator=(data_t val);
};

#ifdef USE_FP16
typedef seq_Vector<int, __fp16, 1> seq_Vector_I32F16_DOF1;
typedef seq_Vector<int, __fp16, 2> seq_Vector_I32F16_DOF2;
typedef seq_Vector<int, __fp16, 3> seq_Vector_I32F16_DOF3;
typedef seq_Vector<int, __fp16, 4> seq_Vector_I32F16_DOF4;
#endif
typedef seq_Vector<int, float , 1> seq_Vector_I32F32_DOF1;
typedef seq_Vector<int, float , 2> seq_Vector_I32F32_DOF2;
typedef seq_Vector<int, float , 3> seq_Vector_I32F32_DOF3;
typedef seq_Vector<int, float , 4> seq_Vector_I32F32_DOF4;

typedef seq_Vector<int, double, 1> seq_Vector_I32F64_DOF1;
typedef seq_Vector<int, double, 2> seq_Vector_I32F64_DOF2;
typedef seq_Vector<int, double, 3> seq_Vector_I32F64_DOF3;
typedef seq_Vector<int, double, 4> seq_Vector_I32F64_DOF4;


template<typename idx_t, typename data_t, typename res_t, int dof>
res_t seq_vec_dot(const seq_Vector<idx_t, data_t, dof> & x, const seq_Vector<idx_t, data_t, dof> & y);
extern template double seq_vec_dot(const seq_Vector_I32F32_DOF1 &, const seq_Vector_I32F32_DOF1 &);
extern template double seq_vec_dot(const seq_Vector_I32F32_DOF2 &, const seq_Vector_I32F32_DOF2 &);
extern template double seq_vec_dot(const seq_Vector_I32F32_DOF3 &, const seq_Vector_I32F32_DOF3 &);
extern template double seq_vec_dot(const seq_Vector_I32F32_DOF4 &, const seq_Vector_I32F32_DOF4 &);
extern template double seq_vec_dot(const seq_Vector_I32F64_DOF1 &, const seq_Vector_I32F64_DOF1 &);
extern template double seq_vec_dot(const seq_Vector_I32F64_DOF2 &, const seq_Vector_I32F64_DOF2 &);
extern template double seq_vec_dot(const seq_Vector_I32F64_DOF3 &, const seq_Vector_I32F64_DOF3 &);
extern template double seq_vec_dot(const seq_Vector_I32F64_DOF4 &, const seq_Vector_I32F64_DOF4 &);

template<typename idx_t, typename data_t, typename res_t, int dof>
res_t seq_vec_inf_norm(const seq_Vector<idx_t, data_t, dof> & x, long long* max_index);
extern template double seq_vec_inf_norm(const seq_Vector_I32F32_DOF1 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F32_DOF2 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F32_DOF3 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F32_DOF4 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F64_DOF1 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F64_DOF2 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F64_DOF3 &, long long* );
extern template double seq_vec_inf_norm(const seq_Vector_I32F64_DOF4 &, long long* );

template<typename idx_t, typename data_t, typename scalar_t, int dof>
void seq_vec_add(const seq_Vector<idx_t, data_t, dof> & v1, scalar_t alpha, 
                 const seq_Vector<idx_t, data_t, dof> & v2, seq_Vector<idx_t, data_t, dof> & v);
extern template void seq_vec_add(const seq_Vector_I32F32_DOF1 &, float , const seq_Vector_I32F32_DOF1 &, seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_add(const seq_Vector_I32F32_DOF2 &, float , const seq_Vector_I32F32_DOF2 &, seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_add(const seq_Vector_I32F32_DOF3 &, float , const seq_Vector_I32F32_DOF3 &, seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_add(const seq_Vector_I32F32_DOF4 &, float , const seq_Vector_I32F32_DOF4 &, seq_Vector_I32F32_DOF4 &);
extern template void seq_vec_add(const seq_Vector_I32F64_DOF1 &, double, const seq_Vector_I32F64_DOF1 &, seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_add(const seq_Vector_I32F64_DOF2 &, double, const seq_Vector_I32F64_DOF2 &, seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_add(const seq_Vector_I32F64_DOF3 &, double, const seq_Vector_I32F64_DOF3 &, seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_add(const seq_Vector_I32F64_DOF4 &, double, const seq_Vector_I32F64_DOF4 &, seq_Vector_I32F64_DOF4 &);
                 
template<typename idx_t, typename data_t, int dof>
void seq_vec_copy(const seq_Vector<idx_t, data_t, dof> & src, seq_Vector<idx_t, data_t, dof> & dst);
extern template void seq_vec_copy(const seq_Vector_I32F32_DOF1 &, seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_copy(const seq_Vector_I32F32_DOF2 &, seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_copy(const seq_Vector_I32F32_DOF3 &, seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_copy(const seq_Vector_I32F32_DOF4 &, seq_Vector_I32F32_DOF4 &);
extern template void seq_vec_copy(const seq_Vector_I32F64_DOF1 &, seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_copy(const seq_Vector_I32F64_DOF2 &, seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_copy(const seq_Vector_I32F64_DOF3 &, seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_copy(const seq_Vector_I32F64_DOF4 &, seq_Vector_I32F64_DOF4 &);

template<typename idx_t, typename data_t, typename scalar_t, int dof>
void seq_vec_mul_by_scalar(const scalar_t coeff, const seq_Vector<idx_t, data_t, dof> & src, seq_Vector<idx_t, data_t, dof> & dst);
extern template void seq_vec_mul_by_scalar(const float , const seq_Vector_I32F32_DOF1 &, seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_mul_by_scalar(const float , const seq_Vector_I32F32_DOF2 &, seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_mul_by_scalar(const float , const seq_Vector_I32F32_DOF3 &, seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_mul_by_scalar(const float , const seq_Vector_I32F32_DOF4 &, seq_Vector_I32F32_DOF4 &);
extern template void seq_vec_mul_by_scalar(const double, const seq_Vector_I32F64_DOF1 &, seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_mul_by_scalar(const double, const seq_Vector_I32F64_DOF2 &, seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_mul_by_scalar(const double, const seq_Vector_I32F64_DOF3 &, seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_mul_by_scalar(const double, const seq_Vector_I32F64_DOF4 &, seq_Vector_I32F64_DOF4 &);

template<typename idx_t, typename data_t, typename scalar_t, int dof>
void seq_vec_scale(const scalar_t coeff, seq_Vector<idx_t, data_t, dof> & vec);
extern template void seq_vec_scale(const float , seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_scale(const float , seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_scale(const float , seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_scale(const float , seq_Vector_I32F32_DOF4 &);
extern template void seq_vec_scale(const double, seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_scale(const double, seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_scale(const double, seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_scale(const double, seq_Vector_I32F64_DOF4 &);

template<typename idx_t, typename data_t1, typename data_t2, int dof>
void seq_vec_elemwise_mul(seq_Vector<idx_t, data_t1, dof> & inout_vec, const seq_Vector<idx_t, data_t2, dof> & scaleplate);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF1 &, const seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF2 &, const seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF3 &, const seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF4 &, const seq_Vector_I32F32_DOF4 &);

extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF1 &, const seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF2 &, const seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF3 &, const seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF4 &, const seq_Vector_I32F64_DOF4 &);

extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF1 &, const seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF2 &, const seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF3 &, const seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF4 &, const seq_Vector_I32F64_DOF4 &);

extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF1 &, const seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF2 &, const seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF3 &, const seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF4 &, const seq_Vector_I32F32_DOF4 &);
#ifdef USE_FP16
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF1 &, const seq_Vector_I32F16_DOF1 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF2 &, const seq_Vector_I32F16_DOF2 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF3 &, const seq_Vector_I32F16_DOF3 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F64_DOF4 &, const seq_Vector_I32F16_DOF4 &);

extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF1 &, const seq_Vector_I32F16_DOF1 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF2 &, const seq_Vector_I32F16_DOF2 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF3 &, const seq_Vector_I32F16_DOF3 &);
extern template void seq_vec_elemwise_mul(seq_Vector_I32F32_DOF4 &, const seq_Vector_I32F16_DOF4 &);
#endif

template<typename idx_t, typename data_t1, typename data_t2, int dof>
void seq_vec_elemwise_div(seq_Vector<idx_t, data_t1, dof> & inout_vec, const seq_Vector<idx_t, data_t2, dof> & scaleplate);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF1 &, const seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF2 &, const seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF3 &, const seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF4 &, const seq_Vector_I32F32_DOF4 &);

extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF1 &, const seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF2 &, const seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF3 &, const seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF4 &, const seq_Vector_I32F64_DOF4 &);

extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF1 &, const seq_Vector_I32F64_DOF1 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF2 &, const seq_Vector_I32F64_DOF2 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF3 &, const seq_Vector_I32F64_DOF3 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F32_DOF4 &, const seq_Vector_I32F64_DOF4 &);

extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF1 &, const seq_Vector_I32F32_DOF1 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF2 &, const seq_Vector_I32F32_DOF2 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF3 &, const seq_Vector_I32F32_DOF3 &);
extern template void seq_vec_elemwise_div(seq_Vector_I32F64_DOF4 &, const seq_Vector_I32F32_DOF4 &);


template<typename idx_t, typename data_t, typename calc_t, int dof>
class CSRMatrix
{
public:
    idx_t nrows = 0;// 行数
    idx_t ncols = 0;// 列数
    idx_t nnz   = 0;// 非零元数
    idx_t * row_ptr = nullptr;// 行偏移量
    idx_t * col_idx = nullptr;// 列索引
    data_t* vals = nullptr;// 非零元值

    CSRMatrix();
    CSRMatrix(const idx_t _nrows, const idx_t _ncols);
    CSRMatrix(const idx_t _nrows, const idx_t _ncols, const idx_t _nnz);
    ~CSRMatrix();

    // not thread-safe !!!
    void alloc_mem(bool zero_rpt = true);
    // y := alpha*A*x + beta*b
    void Mult(calc_t alpha, const calc_t *x, calc_t beta, const calc_t * b, calc_t *y) const;

    void transpose(CSRMatrix<idx_t, data_t, calc_t, dof> & myT);
};
typedef CSRMatrix<int, float , float , 1> CSRMatrix_I32F32F32_DOF1;
typedef CSRMatrix<int, float , float , 2> CSRMatrix_I32F32F32_DOF2;
typedef CSRMatrix<int, float , float , 3> CSRMatrix_I32F32F32_DOF3;
typedef CSRMatrix<int, float , float , 4> CSRMatrix_I32F32F32_DOF4;

typedef CSRMatrix<int, float , double, 1> CSRMatrix_I32F32F64_DOF1;
typedef CSRMatrix<int, float , double, 2> CSRMatrix_I32F32F64_DOF2;
typedef CSRMatrix<int, float , double, 3> CSRMatrix_I32F32F64_DOF3;
typedef CSRMatrix<int, float , double, 4> CSRMatrix_I32F32F64_DOF4;

typedef CSRMatrix<int, double, double, 1> CSRMatrix_I32F64F64_DOF1;
typedef CSRMatrix<int, double, double, 2> CSRMatrix_I32F64F64_DOF2;
typedef CSRMatrix<int, double, double, 3> CSRMatrix_I32F64F64_DOF3;
typedef CSRMatrix<int, double, double, 4> CSRMatrix_I32F64F64_DOF4;
#ifdef USE_FP16
typedef CSRMatrix<int, __fp16, float , 1> CSRMatrix_I32F16F32_DOF1;
typedef CSRMatrix<int, __fp16, float , 2> CSRMatrix_I32F16F32_DOF2;
typedef CSRMatrix<int, __fp16, float , 3> CSRMatrix_I32F16F32_DOF3;
typedef CSRMatrix<int, __fp16, float , 4> CSRMatrix_I32F16F32_DOF4;

typedef CSRMatrix<int, __fp16, double, 1> CSRMatrix_I32F16F64_DOF1;
typedef CSRMatrix<int, __fp16, double, 2> CSRMatrix_I32F16F64_DOF2;
typedef CSRMatrix<int, __fp16, double, 3> CSRMatrix_I32F16F64_DOF3;
typedef CSRMatrix<int, __fp16, double, 4> CSRMatrix_I32F16F64_DOF4;
#endif

#endif